perm filename RUNTIM.PUB[HAL,HE] blob
sn#119204 filedate 1974-09-06 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00006 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 .NEWSEC RUNTIME SYSTEM
C00009 00003 .NEWSS (PHILOSOPHY OF SERVOING,SERVOING)
C00018 00004 .NEWSS (TRAJECTORIES,TRAJECTORIES)
C00021 00005 .NEWSS INTERPRETABLE CODE
C00029 00006 .gpa:NEWSS(ALGORITHMS FOR USE OF GRAPH STRUCTURE,GRAPH ALGORITHMS)
C00032 ENDMK
C⊗;
.NEWSEC RUNTIME SYSTEM
This appendix discusses in greater detail some of the aspects
of the runtime system, which resides on the PDP11 as a set of programs
executing compiled code, operating devices in real time and receiving
sensory input.
.NEWSS (THE RUNTIME SCHEDULER,THE SCHEDULER)
As mentioned earlier, in chapter 7, the runtime scheduling is
managed through a combination of priority level assignments to
various types of processes and a time-slot request list.
The PDP-11 hardware provides eight processor priority levels. These
are assigned in the HAL system as follows:
.BEGIN
.TABBREAK
.PREFACE 0
.NARROW 8,8
7. AD (Analog-to-digital converter), joint servoing
6. Clock, calendar
5. <spare>
4. ON condition checkers; Interrupt handlers for
various condition-checking devices (eg finger pads).
3. servo predictor
2. <spare>
1. Interpreters, scheduler for background stuff.
0. Interpreters
.END
The HAL system keeps a calendar of things that must be done
in each time interval. With time slot is associated:
.BEGIN
.TABBREAK
.PREFACE 0
.NARROW 8,8
a. An AD command list which is to be started.
b. A queue of procedure calls to make at various priority
levels.
.END
When the clock ticks, the clock interrupt routine starts
running in kernel mode. The first thing it does is to start the
specified AD command list, if any. (This will cause an AD-done
interrupt in around 20-30 microseconds.) Finally, it uses the
software interrupts to arrange for all of the queued procedure calls
to take place at the appropriate levels.
The AD service routine runs at priority level 7, and
uses register set zero. However, it does run in user mode, thus
safeguarding the rest of the system from bugs. The AD command list
consists of a sequential table of two word entries:
.BEGIN TABBREAK NARROW 8,8; PREFACE 0;
a. CHNCMD -- channel command
b. SAMPLE -- usually, a slot for storing a sample value.
.END
Essentially, the AD service routine keeps an internal
variable that points to the entry in the command list corresponding
to the most recent (current) AD channel command. When an AD-done
interrupt occurs, the service routine copies the contents of the AD
value register into the current SAMPLE slot. It then increments its
pointer to point at the next two word entry. If CHNCMD of the new
entry is non-zero, it issues the appropriate command and dismisses.
If CHNCMD is zero, then SAMPLE is assumed to be the address of some
code to be executed (typically, a servo). In this case, the AD
service routine will just clear its internal pointer (to signify that
it is done), and jump to the indicated address.
Typically, a servoing operation will have two "phases", one
which runs at level 7 as a response to an AD-done interrupt and which is
responsible for emitting the new drive, and a somewhat lower priority
one which requests a new time slot from the calendar management
routine and sets up the correction phase for the new slot. As
previously indicated, this first phase is "scheduled" by putting a
pointer to the appropriate AD command list into the "AD request" part
of a calendar time slot. The second phase is scheduled merely by
entering it onto the calendar queue of things to be requested in the
same tick. Joint servos are described more fully in the next section.
If a non-critical process (eg, an ON-monitor) needs a
"consistent" set of AD measurements, it can get them by setting up
the appropriate AD command list, finding a time slot for taking the
measurements, and then placing a request that the computation that is
to use the set of measurements be started up at the time slot after
the one in which the measurements are made.
In cases where a command list is too long to be finished in
one time slot, the process requesting the measurements must reserve
two (or more) contiguous slots. This is done by placing the command
list id in the first slot and a special flag value (perhaps -1) into
the remaining slots, so that no other processes will try to reserve
them.
.NEWSS (PHILOSOPHY OF SERVOING,SERVOING)
Control of the manipulators is entirely within the computer.
Position, velocity and force information are read into the computer
and motor drive level is output by the computer at whatever rate the
servo can accomplish.
The control of manipulators could be analog but even in
the simplest mode of operation, position servoing, it is necessary to
consider coordinated motion of all six joints along a trajectory
defined by a sequence of polynomials. In performing tasks, such a
screwing in screws, motion is more complex, involving a combination
of position, velocity and force servoing; the mode changes in
response to external and internal stimuli. Even if many modes of
analog servoing were provided it would still be necessary to inform
the computer of all the servo information in order for it to interact
correctly. We close all servo loops within the computer
itself and use no analog servos at all. Closing the servo loop in the
computer requires very little additional computation as the computer
must essentially perform a servo calculation in order to decide
which servo mode to use and what set point to output.
The limitations imposed by use of the computer for servoing
are bandwidth and the noise of digitizing. The computer servo is a sampled
data system of quite low sample rate. These limitations can be
corrected, in part, by providing high frequency velocity feedback in
analog form, without affecting the computer servo.
.NEWSS (JOINT SERVOING,SERVOING)
Any coordinated motion of the arm can be expressed as six
time dependent motions, one for each joint; the coordinated motion is
parameterized in terms of time. The problem of servoing the arm, or
arms, is thus reduced to a problem of servoing a number of joints
with respect to time.
A joint servo has two parts: a drive part and a predictor
part. As mentioned before, the drive part is run at priority level 7.
When it finishes, the servo enters priority level 3 for the
predictor. First, the predictor reserves a time for the next run of
this servo. The delay is chosen based on considerations of joint
response time, joint velocity, and availability of time slots.
Now the predictor evaluates the motion polynomial for the
time which it has reserved. This evaluation may take into account an
interpolating polynomial used for last-minute trajectory
modification, as well as any offset that might be necessary due to
modifications being made during the motion itself. These calculations
give the predicted set point. The predicted velocity and
acceleration are obtained by difference techniques based on recent
set point values. The joint inertia and gravity force loading are
interpolated. The gravity loading is added to the product of the
predicted acceleration and the joint inertia to yield a predicted
drive.
If this joint has multiple wipers then the appropriate wiper
to read the joint position is determined. Then the joint calibration
is applied to the set point to yield the expected potentiometer
reading for the joint at the reserved time. The servo gains, which
are dependent on joint inertia, are next calculated, and finally the
servo equation is set up in terms of observed position and velocity.
The form of the servo equation is dependent on whether the
joint is being run with position, velocity, or force servoing.
Having done all this predictive work, the joint servo dismisses
control.
When the reserved time occurs, the drive part of the servo
runs in priority level 7. The drive part measures the position and
velocity, evaluates the servo equation prepared by the predictor,
applies friction compensation and drives the joint. This is a very
fast computation and minimizes any delay between observation and
action. The predictor is then run again for the next servo
scheduling, as described above.
Upon completion of the motion, or if some error should occur,
or if some other process requests that the joint stop, completion
codes are set for the joint, and then the servo terminates.
The advantage of this servo scheme is that it allows flexible
scheduling: each joint can run at its own required repetition rate.
As the joint knows when it will be run next it is possible to
pre-compute most of the drive and thus reduce the servo delay.
Each servo routine has a control block which includes a status
register. In the
case of a joint servo the status register contains the following
bits:
.UNFILL;
RUN joint is running or about to be run
FIRST first time through loop for this motion.
FINAL in final state, nulling errors
STOP stop this joint, or joint is stopped
EXFORCE joint stopped due to excessive force.
ADERR a/d error
NONEX joint is down or does not exist
STERR servo was not run on schedule
SERVO position servo
VELS velocity servo
FORCE exert force
WOB perturb this joint while running
NUL null errors at end and stop
.REFILL
When the servo is started up for the first time, it is given
certain information, including which joint it should
servo, what the properties of that joint are, what polynomial to
follow, the predicted gravity torque and inertia loadings.
.NEWSS (TRAJECTORIES,TRAJECTORIES)
A trajectory for the hand is generated at compile time
under the assumption that the planning values for
the initial point, departure point, via points,
arrival point and final position are accurate.
If at run time it is found that some or all of these planned
positions have moved slightly it becomes necessary to modify the
planned trajectory to pass through the actual positions. If the
actual positions are only slightly different from the planned
positions then the trajectory is still almost optimal, that is, it
still has most of the properties with which it was designed. If the
deviation from the planned values to the actual are great then the
trajectory is no longer optimal. To plan a new trajectory would
again optimize the move, but only if the time to compute is less than
the time saved is it worth recomputing. At present this is not the
case, so no recalculation of trajectories is done. Instead, the
following trajectory modification step is performed:
Before the move is executed, it is prepared by computing the
discrepancies between actual locations and planned locations. Fifth
degree interpolating polynomials (with zero initial and final
velocity and acceleration) are computed to be added into the planned
polynomials to bring the planned trajectory into line with reality.
The joint angles associated with a frame are stored along with its
matrix, so this often does not involve much calculation, unless the
frame has been changed since these calculations were done last. Also
at this time the joint inertias and gravity loadings are calculated
and stored in the value cell of relevant frames.
.NEWSS INTERPRETABLE CODE
The basic instruction emitted by the compiler is one 16-bit
word. The first 8 bits are the opcode, and the last 8 are used to
form the operand address, if the opcode needs one. Addressing modes
are either immediate, in which case the next word has the address, or
relative (to the program counter). Immediate addressing is indicated
by the second byte being 0. Anything else is relative addressing;
bit 8 (the lefthand bit of the righthand byte) is a sign bit; thus
one can look 127 locations forward or backward; the full word address
will be found at this place. Full-word addresses can be indirect;
this is indicated by a high-order bit (ie, bit 0) being 1.
Indirection can proceed to any level.
.SKIP SPREAD
←STACK OPERATORS
.BEGIN INDENT 0,16
.PREFACE 0
pushadr <arg> \puts <arg> on top of the stack. It is assumed that
<arg> is the address of a variable.
pushval <arg> \puts value of variable pointed to by <arg> on stack.
gets good value, if necessary.
pop \pops the stack.
copy <num> \finds the <num>'th element down in the stack, and copies
it to the top.
flush \clears the stack.
store <arg> \pointer at top of stack copied into value pointer at <arg>;
stack is popped.
.END
←SINGLE FRAME OPERATIONS
.BEGIN INDENT 0,16
.PREFACE 0
solve \takes a pointer to a frame value cell from top of stack.
Generates arm solution (if necessary) and stores in the
value cell. The stack is popped.
invert \the inverse of the value cell at top of stack goes to
top of stack; old top popped.
.END
←ARITHMETIC
For the following, the args are on the stack, are popped
after the operation, the answer pointed to on top of stack. Earlier
arguments deeper on the stack.
.BEGIN INDENT 0,16
.PREFACE 0
s+s \scalar addition. 2 args.
s-s \scalar subtraction. 2 args.
s*s \scalar multiplication. 2. args.
s/s \scalar division. error if second arg is 0. 2 args.
|v| \magnitude of vector. 1 arg.
v.v \dot product. returns scalar.
(sss) \forms vector from 3 scalars. 3 args.
s*v \dilation of vector. 2 args. scalar first.
v+v \vector addition. 2 args.
vα∂v \vector rotated by vector. second arg is rotation. 2 args.
t*v \transformation of vector. trans first. 2 args.
[v:v] \forms frame from 2 vectors. first is loc, second orient.
f+v \translation of frame. 2 args. frame first.
fα∂v \rotation of frame. 2 args. frame first.
t*f \transformation of frame. 2 args. frame first.
fα→f \forms trans from two frames. 2 args. f1'f2.
[v|v] \forms trans from two vectors. 1: trans; 2: rot.
t+v \translates trans. 2 args. trans first.
tα∂v \rotates trans. 2 args. trans first.
t*t \composition (to the left) of two transes.
tinv \inverse of trans
.END
←EXTRACTION AND COMPOSITION
.BEGIN INDENT 0,16
.PREFACE 0
loc \location of frame replaces it at top of stack.
orient \orientation of frame replaces it at top of stack.
xscal \x coordinate of vector replaces it at top of stack.
yscal \y coordinate of vector replaces it at top of stack.
zscal \z coordinate of vector replaces it at top of stack.
.END
←PROCESS CONTROL
.BEGIN INDENT 0,16
.PREFACE 0
sprout <arg> \start up an interpreter with program counter <arg>.
enable <arg> \start up an on-monitor with location of status word <arg>.
disable <arg> \the on-monitor with location of status word <arg> is disabled.
wait \wait until all descendant (non on-monitor) processes are dead.
Then kill descendant move on-monitors and continue.
terminate \terminate this process. Should first call "wait".
.END
←JUMPS
.BEGIN INDENT 0,16
.PREFACE 0
This list is not complete.
jump <arg>
nop \no-op.
.END
←ARM AND DEVICE CONTROL
.BEGIN INDENT 0,16
.PREFACE 0
prepmove <arg> \<arg> points to the move vector. Trajectory modification
happens now.
startmove \sprouts joint servos and move-monitors
search <arg> \<arg> points to the search vector.
stop <arg> \<arg> encoding of what devices must be stopped.
.END
←INPUT AND OUTPUT
Some sort of I/O will be implemented, most likely including string
output to the supervisor, error message output, and input (from supervisor
or from coresident routines) of value cells.
←DEBUGGING AIDS
.BEGIN INDENT 0,16
.PREFACE 0
source <arg> \notes that <arg> is where the interpreter is now in
source code.
tellsource \output current source location to the 10.
step \begins step mode, which does one interpretation at a time,
requires message to continue.
offstep \turns off step mode; normal speed is resumed.
.END
.gpa:NEWSS(ALGORITHMS FOR USE OF GRAPH STRUCTURE,GRAPH ALGORITHMS)
These are the algorithms used to find values for variables in the
graph structure and to change those values.
.UNFILL
PROCEDURE invalidate (POINTER(NODE) n);
IF invmark(n)=0 THEN
BEGIN COMMENT: This cell currently marked valid;
POINTER p;
invmark(n)α← -1;
p α← dependents(n);
WHILE p%7≠%*NULL DO
BEGIN COMMENT: Mark all dependents as invalid;
invalidate(p);
p α← link(p)
END
END;
.REFILL
.UNFILL
PROCEDURE change (POINTER(NODE) n; POINTER(VALUE) vnew);
BEGIN
COMMENT: This procedure is called in order to explicitly assign
a new value, vnew, to node n;
POINTER(VALUE) vold;
invalidate(n);
vold α← value(n);
value(n)α←vnew;
p α← changer(n);
WHILE p%7≠%*NULL DO
BEGIN COMMENT: Handle all changers;
APPLY(code(p),vold,vnew);
p α← link(p);
END;
invmark(n) α← 0;
END;
.REFILL
.UNFILL
POINTER(VALUE) PROCEDURE getvalue (POINTER(NODE) n);
BEGIN
IF invmark(n)%7≠%*0 THEN evalnode(n, time α← time+1);
RETURN(value(n));
END;
.REFILL
.UNFILL
PROCEDURE evalnode (POINTER(NODE) n, INTEGER t);
BEGIN COMMENT: Put a good value in the value cell of n.
t is used to break cycles;
IF invmark(n)=0 ∨ invmark(n)=t THEN RETURN;
invmark(n) α← t;
p α← calculator(n);
WHILE p %7≠%* NULL DO
BEGIN "cloop"
POINTER(node) d;
d α← needed(p);
WHILE d %7≠%* NULL DO
BEGIN
evalnode(node(d),t);
IF invmark(dep(d))%7≠%*0 THEN
BEGIN
p α← next(p);
CONTINUE "cloop";
END;
d α← next(d);
END;
value(n)α←APPLY(code(p), args(p));
invmark(n)α←0;
RETURN;
END;
END;
.REFILL